package com.lh.center.common.web.handle;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lh.center.common.constant.GlobalConstant;
import com.lh.center.common.exception.CommonException;
import com.lh.center.common.exception.ErrorEnum;
import com.lh.center.common.web.advice.JsonRequestAdvice;
import com.lh.center.common.web.session.SessionOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.PathMatcher;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Set;

/**
 * 请求体为raw类型时进入本拦截器
 */
@Slf4j
@Component
public class JsonRequestHandle  extends MappingJackson2HttpMessageConverter {

    private final ObjectMapper objectMapper;

    @Lazy
    @Resource
    private JsonRequestAdvice jsonRequestAdvice;

    public JsonRequestHandle(ObjectMapper objectMapper) {
        super(objectMapper);
        this.objectMapper = objectMapper;
    }

    /**
     * type:请求controller中的参数类型
     * contextClass:请求的controller类
     * inputMessage:请求的body体
     */
    @Override
    public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {

        //读取用户的请求数据
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        int i;
        while ((i = inputMessage.getBody().read()) != -1) {
            stream.write(i);
        }
        JavaType javaType = getJavaType(type, contextClass);
        //读取到原始请求数据
        String text = stream.toString();
        text = jsonRequestAdvice.afterReader(text,type,javaType);
        //是否需要做解密处理
        text = toSecret(text);
        text = jsonRequestAdvice.afterSecret(text,type,contextClass);
        //包装接口对应的实体对象
        Object body = this.objectMapper.readerFor(javaType).readValue(text);
        if(JSONUtil.isJsonObj(text)){
            SessionOperation.requestParams.set(JSONUtil.toBean(text,body.getClass()));
        }else if(JSONUtil.isJsonArray(text)){
            SessionOperation.requestParams.set(JSONUtil.parseArray(text));
        }else{
            throw new CommonException("当前请求非json数据");
        }
        if(!jsonRequestAdvice.validate(body)){
            return body;
        }
        //手动参数校验
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<Object>> validate = validator.validate(body);
        if(validate!=null && validate.size()>0){
            for (ConstraintViolation<Object> violation : validate) {
                if(StringUtils.isNotBlank(violation.getMessage())){
                    throw new CommonException(violation.getMessage());
                }
            }
        }
        return body;
    }


    private String toSecret(String text) {
        String enableSecret = SessionOperation.getRequest().getHeader(GlobalConstant.header_enable_secret);
        if(StringUtils.isBlank(enableSecret) || enableSecret.equalsIgnoreCase("false")){
            return text;
        }
        String secret = SessionOperation.getRequest().getHeader(GlobalConstant.header_secret_key);
//        SessionUser user = SessionOperation.getUserNotException();
//        if(user==null || !user.isSecretEnabled()){
//            return text;
//        }
//        String secret = SessionOperation.getUser().getSecret();
        try {
            AES aes = SecureUtil.aes(secret.getBytes());
            String replaceText = text.replace("\"","");
            return aes.decryptStr(replaceText);
        }catch (Exception e) {
            if(!SessionOperation.toAuth.get()){
                return text;
            }
            Set<String> notSecretUri = SessionOperation.getConfiguration().getNotSecretUri();
            if(!CollectionUtils.isEmpty(notSecretUri)){
                PathMatcher matcher = new AntPathMatcher();
                String requestURI = SessionOperation.getRequest().getRequestURI();
                boolean match = notSecretUri.stream().anyMatch(uri -> matcher.match(uri, requestURI));
                if(match){
                    return text;
                }
            }
            throw new CommonException(ErrorEnum.aes_decrypt_error);
        }
    }

    @Override
    protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {

        super.writeInternal(object, type, outputMessage);
    }
}
